/*
 * OPIAM Suite
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package opiam.admin.faare.unittests;

import org.apache.log4j.Logger;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;

import java.util.ArrayList;
import java.util.List;



/**
 * This class contains the common methods used for the tests.
 *
 */
public class TestUtils
{
    /** Message prefix. */
    private static final String PREFIX = " TEST - ";

    /** Class message prefix. */
    private static final String PREFIX_CLASS = " TEST - class : ";

    /** Beginning message. */
    private static final String BEGIN_TEST = " BEGIN CLASS TEST ";

    /** End message. */
    private static final String END_TEST = " END CLASS TEST ";

    /** Beginning method message. */
    private static final String BEGIN_METHOD = PREFIX + " method : ";

    /** End method message. */
    private static final String END_METHOD = PREFIX + " End ";

    /** Success result message. */
    private static final String RESULT_SUCCESS = " ** RESULT => Test OK              ** ";

    /** Failure result message. */
    private static final String RESULT_FAILURE = " ** RESULT => Test NOT OK          ** ";

    /** Error result message. */
    private static final String RESULT_ERROR = " ** RESULT => Unexpected exception ** ";

    /** Indicator result message. */
    private static final String RESULT_INDICATOR = " ** --------------------- ** ";

    /** Indicator next message. */
    public static final String NEXT = "\n";

    /** Indicator empty message. */
    public static final String EMPTY = "";

    /** Limit size of the line. */
    private static final int LINE_SIZE = 80;

    /** Instance of logger. */
    private static Logger _logger = Logger.getLogger(TestUtils.class);

    /**
     * Constructor that defines the logger.
     * @param log Logger.
     */
    public TestUtils(Logger log)
    {
        if (log != null)
        {
            _logger = log;
        }
    }

    /**
     * This method displays the test message.
     *
     * @param msg  Message to display.
     */
    private void display(String msg)
    {
        _logger.warn(centerLine(msg));
    }

    /**
     * Formats the line to center the message.
     *
     * @param line  String to format.
     *
     * @return Formatted line.
     */
    private String centerLine(String line)
    {
        /*        int rab = LINE_SIZE - line.length();
                int frontSpace = rab / 2;
                int backSpace = rab - frontSpace;

                StringBuffer fLine = new StringBuffer();

                for (int i = 0; i < frontSpace; i++)
                {
                    fLine.append(' ');
                }

                fLine.append(line);

                for (int i = 0; i < backSpace; i++)
                {
                    fLine.append(' ');
                }

                return fLine.toString();
        */
        return line;
    }

    /**
     * Displays message with the test prefix.
     *
     * @param msg  Message to display.
     */
    public void displayMsg(String msg)
    {
        int ind = msg.indexOf(NEXT);
        int indLeft = 0;

        while (ind >= 0)
        {
            display(PREFIX + msg.substring(indLeft, ind).trim());

            indLeft = ind + NEXT.length();
            ind = msg.indexOf(NEXT, indLeft);
        }

        display(PREFIX + msg.substring(indLeft));
    }

    /**
     * Displays a success message.
     *
     * @param msg  Description to display with the message.
     */
    public void displayResultSuccess(String msg)
    {
        if (msg != null)
        {
            displayMsg(RESULT_INDICATOR);
            displayMsg(RESULT_SUCCESS);
            displayMsg(msg);
            displayMsg(RESULT_INDICATOR);
        }
        else
        {
            displayMsg(RESULT_SUCCESS);
        }

        TestResult.getInstance().addSuccess(msg);
    }

    /**
     * Displays a failure message.
     *
     * @param msg  Description to display with the message.
     */
    public void displayResultFailure(String msg)
    {
        if (msg != null)
        {
            displayMsg(RESULT_INDICATOR);
            displayMsg(RESULT_FAILURE);
            displayMsg(msg);
            displayMsg(RESULT_INDICATOR);
        }
        else
        {
            displayMsg(RESULT_FAILURE);
        }

        TestResult.getInstance().addFailure(msg);
    }

    /**
     * Displays an error message when an unexpected exception occurs.
     *
     * @param msg  Description to display with the message.
     */
    public void displayResultError(String msg)
    {
        if (msg != null)
        {
            displayMsg(RESULT_INDICATOR);
            displayMsg(RESULT_ERROR);
            displayMsg(msg);
            displayMsg(RESULT_INDICATOR);
        }
        else
        {
            displayMsg(RESULT_ERROR);
        }

        TestResult.getInstance().addErrors(msg);
    }

    /**
     * Displays the header for the class test.
     *
     * @param header  Message to display.
     */
    public void displayHeaderClass(String header)
    {
        display("");
        display(" <<<<<<<<<<<<<<< " + BEGIN_TEST + " >>>>>>>>>>>>>>> ");

        if (header != null)
        {
            display(PREFIX_CLASS + header);
        }

        display("");

        TestResult.getInstance().beginTestClass(header);
    }

    /**
     * Displays the footer for the class test.
     *
     * @param footer  Message to display.
     */
    public void displayFooterClass(String footer)
    {
        if (footer != null)
        {
            display(PREFIX + footer);
        }

        display("");
        display(" >>>>>>>>>>>>>>> " + END_TEST + " <<<<<<<<<<<<<<< ");
        display("");

        TestResult.getInstance().endTestClass();
    }

    /**
     * Displays the header for the method test.
     *
     * @param header  Message to display.
     */
    public void displayHeaderMethod(String header)
    {
        display("");
        display(" ========== " + BEGIN_METHOD + header + " ========== ");
        display("");

        TestResult.getInstance().beginTestMethod(header);
    }

    /**
     * Displays the footer for the method test.
     *
     * @param footer  Message to display.
     */
    public void displayFooterMethod(String footer)
    {
        display("");
        display(" ========== " + END_METHOD + footer + " ========== ");
        display("");

        TestResult.getInstance().endTestMethod();
    }

    /**
     * Compares two values and displays the result.
     *
     * @param refValue  The reference value.
     * @param cmpValue  The comparaison value.
     *
     * @return true if equal, false if not equal
     */
    public boolean compareValues(String refValue, String cmpValue)
    {
        displayMsg("Reference value   : " + refValue);
        displayMsg("Comparaison value : " + cmpValue);

        if (refValue.equals(cmpValue))
        {
            displayResultSuccess(null);

            return true;
        }
        else
        {
            displayResultFailure(null);

            return false;
        }
    }

    /**
     * Displays the tests results for the methods of a given class.
     *
     * @param tClass  The given class.
     */
    private void displayMethodsStatement(TestClass tClass)
    {
        display("       ---------------------------------------      ");
        display("       ----- METHODS : SUCCESSFULLY TESTS ----      ");
        display("       ---------------------------------------      ");
        display(NEXT);

        ArrayList methodsList = tClass.getMethodsSuccess();

        for (int j = 0; j < methodsList.size(); j++)
        {
            TestMethod tMethod = (TestMethod) methodsList.get(j);

            display("    Method : " + tMethod.getMethodName());
            display(EMPTY);
            display("           Number of tests          : " +
                tMethod.getTestsNumber());
            display(EMPTY);
            display("              of which in error     : " +
                tMethod.getErrorTestsNumber());
            display("                       in failure   : " +
                tMethod.getFailureTestsNumber());
            display("                       successfully : " +
                tMethod.getSuccessTestsNumber());
            display(EMPTY);
            display("       ---------------------------------------      ");
            display(EMPTY);
        }

        display("       ---------------------------------------      ");
        display("       ----- METHODS : TESTS IN FAILURE ------      ");
        display("       ---------------------------------------      ");
        display(EMPTY);
        methodsList = tClass.getMethodsFailure();

        for (int j = 0; j < methodsList.size(); j++)
        {
            TestMethod tMethod = (TestMethod) methodsList.get(j);

            display("    Method : " + tMethod.getMethodName());
            display(EMPTY);
            display("           Number of tests          : " +
                tMethod.getTestsNumber());
            display(EMPTY);
            display("              of which in error     : " +
                tMethod.getErrorTestsNumber());
            display("                       in failure   : " +
                tMethod.getFailureTestsNumber());
            display("                       successfully : " +
                tMethod.getSuccessTestsNumber());
            display(EMPTY);
            display("       ---------------------------------------      ");
            display(EMPTY);
        }

        display("       ---------------------------------------      ");
        display("       ----- METHOD : TESTS IN ERROR ---------      ");
        display("       ---------------------------------------      ");
        display(EMPTY);
        methodsList = tClass.getMethodsError();

        for (int j = 0; j < methodsList.size(); j++)
        {
            TestMethod tMethod = (TestMethod) methodsList.get(j);

            display("    Method : " + tMethod.getMethodName());
            display(EMPTY);
            display("           Number of tests          : " +
                tMethod.getTestsNumber());
            display(EMPTY);
            display("              of which in error     : " +
                tMethod.getErrorTestsNumber());
            display("                       in failure   : " +
                tMethod.getFailureTestsNumber());
            display("                       successfully : " +
                tMethod.getSuccessTestsNumber());
            display(EMPTY);
            display("       ---------------------------------------      ");
            display(EMPTY);
        }
    }

    /**
     * Displays the tests results for the classes.
     */
    private void displayClassesStatement()
    {
        display(EMPTY);
        display("       ---------------------------------------      ");
        display("       ---- CLASSES : SUCCESSFULLY TESTS -----      ");
        display("       ---------------------------------------      ");
        display(EMPTY);

        ArrayList classesList = TestResult.getInstance().getSuccessClassTests();

        for (int i = 0; i < classesList.size(); i++)
        {
            TestClass tClass = (TestClass) classesList.get(i);

            display("****************************************************");
            display("    CLASS : " + tClass.getClassName());
            display(EMPTY);
            display("           Number of tested methods : " +
                tClass.getMethodTestsNumber());
            display(EMPTY);
            display("             of  which in error     : " +
                tClass.getErrorTestsNumber());
            display("                       in failure   : " +
                tClass.getFailureTestsNumber());
            display("                       successfully : " +
                tClass.getSuccessTestsNumber());
            display(EMPTY);
            displayMethodsStatement(tClass);
            display(EMPTY);
            display("****************************************************");
            display(EMPTY);
        }

        display(EMPTY);
        display("       ---------------------------------------      ");
        display("       ---- CLASSES : TESTS IN FAILURE   -----      ");
        display("       ---------------------------------------      ");
        display(EMPTY);
        classesList = TestResult.getInstance().getFailureClassTests();

        for (int i = 0; i < classesList.size(); i++)
        {
            TestClass tClass = (TestClass) classesList.get(i);

            display("****************************************************");
            display("    CLASS : " + tClass.getClassName());
            display(EMPTY);
            display("           Number of tested methods : " +
                tClass.getMethodTestsNumber());
            display(EMPTY);
            display("              of which in error     : " +
                tClass.getErrorTestsNumber());
            display("                       in failure   : " +
                tClass.getFailureTestsNumber());
            display("                       successfully : " +
                tClass.getSuccessTestsNumber());
            display(EMPTY);
            displayMethodsStatement(tClass);
            display(EMPTY);
            display("****************************************************");
            display(EMPTY);
        }

        display(EMPTY);
        display("       ---------------------------------------      ");
        display("       ---- CLASSES : TESTS IN ERROR     -----      ");
        display("       ---------------------------------------      ");
        display(EMPTY);
        classesList = TestResult.getInstance().getErrorClassTests();

        for (int i = 0; i < classesList.size(); i++)
        {
            TestClass tClass = (TestClass) classesList.get(i);

            display("****************************************************");
            display("    CLASS : " + tClass.getClassName());
            display(EMPTY);
            display("           Number of tested methods : " +
                tClass.getMethodTestsNumber());
            display(EMPTY);
            display("              of which in error     : " +
                tClass.getErrorTestsNumber());
            display("                       in failure   : " +
                tClass.getFailureTestsNumber());
            display("                       successfully : " +
                tClass.getSuccessTestsNumber());
            display(EMPTY);
            displayMethodsStatement(tClass);
            display(EMPTY);
            display("****************************************************");
            display(EMPTY);
        }
    }

    /**
     * Displays the result of the set of tests.
     *
     * @param name  The name of the class that wants to display the result.
     */
    public void displayTestStatement(String name)
    {
        if (TestResult.getInstance().isInitiator(name))
        {
            StringBuffer sb = new StringBuffer();

            display(EMPTY);
            sb.append(EMPTY);
            display("====================================================");
            display("TESTS STATEMENT :");
            display("====================================================");
            display(EMPTY);
            display("           Number of tested classes : " +
                TestResult.getInstance().getClassTestsNumber());
            display(EMPTY);
            display("              of which in error     : " +
                TestResult.getInstance().getErrorClassTestsNumber());
            display("                       in failure   : " +
                TestResult.getInstance().getFailureClassTestsNumber());
            display("                       successfully : " +
                TestResult.getInstance().getSuccessClassTestsNumber());
            display(EMPTY);
            display("           Number of tested methods : " +
                TestResult.getInstance().getMethodTestsNumber());
            display(EMPTY);
            display("           Number of tests          : " +
                TestResult.getInstance().getTestsNumber());
            display(EMPTY);
            displayClassesStatement();
            display(EMPTY);
            display("====================================================");
            display(EMPTY);
            display(EMPTY);
        }
    }

    /**
     * Creates a file and writes object to it.
     *
     * @param fileName  Name of the File to create. [Mandatory]
     * @param filePath  Path of the File to create (in windows mode : \\directory\\directory\\ ).
     * @param b  Array of bytes.
     */
    public void createFile(String fileName, String filePath, byte[] b)
    {
        try
        {
            displayMsg("createFile fileName : " + fileName);
            displayMsg("createFile filePath : " + filePath);

            if ((fileName == null) || (fileName.length() < 1))
            {
                throw new Exception("FileName is not defined");
            }

            File file;

            if (filePath == null)
            {
                file = new File(fileName);
            }
            else
            {
                //file = new File(filePath + fileName);
                file = new File(fileName);
            }

            displayMsg("createFile length of the bytes array : " + b.length);

            if (!file.exists())
            {
                file.createNewFile();
            }

            FileOutputStream foutstream = new FileOutputStream(file);
            foutstream.write(b);
            foutstream.close();
        }
        catch (Exception e)
        {
            displayMsg("createFile " + e.toString());
        }
    }

    /**
     * Reads data from file.
     *
     * @param fileName  Name of the file to be read. [Mandatory]
     * @param filePath  Path of the file to be read.
     *
     * @return Read data as a bytes array.
     */
    public byte[] readBytesFromFile(String fileName, String filePath)
    {
        byte[] returnBytes = null;

        try
        {
            displayMsg("readBytesFromFile fileName : " + fileName);
            displayMsg("readBytesFromFile filePath : " + filePath);

            if ((fileName == null) || (fileName.length() < 1))
            {
                throw new Exception("FileName is not defined");
            }

            File file;

            if (filePath == null)
            {
                file = new File(fileName);
            }
            else
            {
                file = new File(filePath + fileName);
            }
            BufferedInputStream bufin = new BufferedInputStream(
                  TestUtils.class.getClassLoader().getResourceAsStream(filePath + fileName));

            List listBytes = new ArrayList();
            int b;
            int i = 0;

            while ((b = bufin.read()) >= 0)
            {
                listBytes.add(new Byte((byte) b));

                i++;
            }

            bufin.close();

            returnBytes = new byte[listBytes.size()];
            for (int j = 0; j < listBytes.size(); j++)
            {
                returnBytes[j] = ((Byte) listBytes.get(j)).byteValue();
            }
        }
        catch (Exception e)
        {
            displayMsg("readBytesFromFile " + e.toString());
        }

        return returnBytes;
    }
}
